#ifndef __SISTEMA_H__
#define __SISTEMA_H__

#include <iostream>
#include <vector>
#include <matriz.h>

using namespace std;

/*
* Representa un sistema de ecuaciones lineales cuadrado del tipo Ax = b.
*/

class sistema{
    public:
        /*Inicializa el sistema de ecuaciones con la matriz cuadrada nula de nxn y con b igual al vector nulo*/
        sistema(unsigned int n);
        
        /*Inicializa el sistema a partir de la matriz A y el vector b
         * IMPORTANTE: el vector b y la matriz A deben coincidir en la cantidad de filas!!! 
         */
        sistema(matriz<double>& A, vector<double>& b);

        /*Inicializa la matriz asociada al sistema*/
        void setMatriz(matriz<double>& A);
        
        /*Inicializa la i-esima fila de la matriz asociada al sistema*/
        void setFila(vector<double>& terminos, unsigned int i);
        
        /*Inicializa el j-esimo termino del a i-esima ecuacion*/
        void setTermino(double a, unsigned int i, unsigned int j);
        
        /*Retorna el j-esimo termino del a i-esima ecuacion*/
        double getTermino(unsigned int i, unsigned int j);

        /*Inicializa el vector de terminos independientes*/
        void setTerminosIndependientes(vector<double>& b);
        
        /*Inicializa el i-esimo termino independiente*/
        void setTerminoIndependiente(double b, unsigned int i);
        
        /*Resuelve el sistema*/
        void resolver();
        
        /*Devuelve el valor de la i-esima incognita*/
        double getIncognita(unsigned int i);
        
        /** Muestra la matriz mediante el ostream pasado */
        void mostrar(std::ostream& out);
        
         /**
        * Intenta triangular la matriz.
        * Devuelve true si se pudo realizar y false si no es inversible.
        * El método trabaja directamente con los elementos de la matriz, por lo cual
        * será modificada sea o no sea inversible.
        */
        bool triangular();
        
        
        
        
        /** Intercambia de lugar dos filas */
        void swapFila(int , int);

        /**
        * Busca el elemento de mayor módulo de la columna
        * a partir de la fila indicada hasta el final, y
        * swapea las filas. 
        */ 
        void pivoteo(int fila, int columna);

        /**
        * Resta a fila1 un múltiplo de fila2.
        */
        void restaAFila(int fila1, int fila2, double coeficiente);
        
        bool hayFilaNula();
        
        bool esFilaNula(matriz<double>& m, int i);

    private:
        /*Indica si el sistema esta resuelto*/
        bool resuelto;
        /*Vector de incognitas*/
        vector<double> x;
        /*Matriz cuadrada del sistema*/
        matriz<double> A;
        /*Vector de terminos independientes*/
        vector<double> b;       
       
};

#endif
